﻿using Abp.Domain.Repositories;
using Abp.Domain.Services;
using Abp.Domain.Uow;
using Mt.Site.Core.Storage;
using Mt.Site.Core.Synchronization.Data;
using System;
using System.Threading.Tasks;

namespace Mt.Site.Core.Synchronization.Storage
{
    public class FileObjectAutoSyncManager : DomainService, IFileObjectAutoSyncManager
    {
        public readonly IRepository<FileObject, Guid> _fileObjectRepository;

        private readonly IUnitOfWorkManager _unitOfWorkManager;

        public readonly ISynchronizationHelper _synchronizationHelper;

        private readonly IFileObjectDataStoreManager _fileObjectDataStoreManager;

        public FileObjectAutoSyncManager(
                IRepository<FileObject, Guid> fileObjectRepository,
                IUnitOfWorkManager unitOfWorkManager,
                ISynchronizationHelper synchronizationHelper,
                IFileObjectDataStoreManager fileObjectDataStoreManager)
        {
            _fileObjectRepository = fileObjectRepository;
            _unitOfWorkManager = unitOfWorkManager;
            _synchronizationHelper = synchronizationHelper;
            _fileObjectDataStoreManager = fileObjectDataStoreManager;
        }

        [UnitOfWork]
        public Guid CreateOrUpdateFileObjectAutoSync(CreateOrUpdateSynchorizeStore input, Guid toContentId)
        {
            using (_unitOfWorkManager.Current.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage,
                AbpDataFilters.SoftDelete))
            {
                var fromEntity = _fileObjectRepository.FirstOrDefault(input.Id);

                if (fromEntity != null)
                {
                    var toEntity = _fileObjectRepository.FirstOrDefault(
                            item => item.SourceID == input.Id && item.Language == input.TargetLanguage && item.TenantId == input.ToTenantId);

                    if (toEntity != null)
                    {
                        return _fileObjectDataStoreManager.UpdateFileObjectSync(toEntity, fromEntity);
                    }
                    else
                    {
                        return _fileObjectDataStoreManager.CreateFileObjectSync(fromEntity,
                                new DataProcessingStore
                                {
                                    TargetLanguage = input.TargetLanguage,
                                    ToTenantId = input.ToTenantId,
                                    AssociateId = toContentId
                                });
                    }
                }
                return Guid.Empty;
            }
        }

        [UnitOfWork]
        public Guid DeleteFileObjectSync(DeleteSyncStore input)
        {
            using (_unitOfWorkManager.Current.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage,
                AbpDataFilters.SoftDelete))
            {
                var toEntity = _fileObjectRepository.FirstOrDefault(
                        item => item.SourceID == input.Id && item.Language == input.TargetLanguage && item.TenantId == input.ToTenantId);

                if (toEntity != null && toEntity.IsDeleted == false)
                {
                    _fileObjectRepository.Delete(toEntity.Id);
                    return toEntity.Id;
                }
                return Guid.Empty;
            }
        }

        [UnitOfWork]
        public async Task<Guid> CreateOrUpdateFileObjectByMenuSync(CreateOrUpdateSynchorizeStore input,Guid toContentId,long menuId)
        {
            using (_unitOfWorkManager.Current.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage,
                AbpDataFilters.SoftDelete))
            {
                var notify = new NoticeArgs();

                try
                {
                    var fromEntity = _fileObjectRepository.FirstOrDefault(input.Id);

                    if (fromEntity != null)
                    {
                        notify.FromId = fromEntity.Id;
                        notify.MenuId = menuId;
                        notify.Title = fromEntity.Title;
                        notify.ToLanguage = input.TargetLanguage;
                        notify.ToTenantId = input.ToTenantId;
                        notify.Type = input.OptionType;

                        var toEntity = _fileObjectRepository.FirstOrDefault(
                                item => item.SourceID == input.Id && item.Language == input.TargetLanguage && item.TenantId == input.ToTenantId);

                        var toFileObjectId = Guid.Empty;
                        if (toEntity == null)
                        {
                            toFileObjectId = _fileObjectDataStoreManager.CreateFileObjectSync(fromEntity, new DataProcessingStore
                            {
                                AssociateId = toContentId,
                                TargetLanguage = input.TargetLanguage,
                                ToTenantId = input.ToTenantId
                            });
                        }
                        else
                        {
                            if (_synchronizationHelper.ShouldSynchronize(toEntity))
                            {
                                toFileObjectId = _fileObjectDataStoreManager.UpdateFileObjectSync(toEntity, fromEntity);
                            }
                            
                        }
                        if (toFileObjectId != Guid.Empty)
                        {
                            notify.ToId = toFileObjectId;
                            await _synchronizationHelper.SendNoticeForSuccessAsync(notify);
                            return toFileObjectId;
                        }

                    }
                    return Guid.Empty;
                }
                catch (Exception)
                {
                    if (notify.FromId != Guid.Empty)
                    {
                        await _synchronizationHelper.SendNoticeForFailAsync(notify);
                    }
                    throw;
                }
            }
        }

        [UnitOfWork]
        public async Task<Guid> DeleteFileObjectByMenuSync(DeleteSyncStore input,long menuId)
        {
            using (_unitOfWorkManager.Current.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage,
                AbpDataFilters.SoftDelete))
            {
                var notify = new NoticeArgs();
                try
                {
                    var fromEntity = _fileObjectRepository.FirstOrDefault(input.Id);

                    if (fromEntity == null)
                    {
                        return Guid.Empty;
                    }
                    notify.FromId = fromEntity.Id;
                    notify.Title = fromEntity.Title;
                    notify.ToLanguage = input.TargetLanguage;
                    notify.ToTenantId = input.ToTenantId;
                    notify.Type = input.OptionType;
                    notify.MenuId = menuId;

                    var toEntity = _fileObjectRepository.FirstOrDefault(
                            item => item.SourceID == input.Id && item.Language == input.TargetLanguage && item.TenantId == input.ToTenantId);

                    if (toEntity != null && toEntity.IsDeleted ==false)
                    {
                        if (_synchronizationHelper.ShouldSynchronize(toEntity))
                        {
                            _fileObjectRepository.Delete(toEntity.Id);
                            notify.ToId = toEntity.Id;
                            await _synchronizationHelper.SendNoticeForSuccessAsync(notify);
                            return toEntity.Id;
                        }
                    }
                    return Guid.Empty;
                }
                catch (Exception)
                {
                    if (notify.FromId != Guid.Empty)
                    {
                        await _synchronizationHelper.SendNoticeForFailAsync(notify);
                    }
                    throw;
                }
            }
        }
    }
}
